import subprocess
import os
import json
import sys
import asyncio
import logging
import time
import threading
import multiprocessing
import queue
import argparse
from fastmcp import FastMCP
from typing import Dict, Any, AsyncIterator, List, Optional
from mcp.server.lowlevel.server import LifespanResultT
from contextlib import asynccontextmanager
import shutil
from pathlib import Path

# 导入子进程模块
import maipu_ai_coder_subprocess

# 处理PyInstaller打包后的多进程问题
# 当作为PyInstaller打包的可执行文件运行时，需要正确处理多进程参数
if getattr(sys, 'frozen', False):
    # 运行在PyInstaller打包后的环境中
    # 不直接设置pythonw.exe路径，让multiprocessing模块自动处理
    # 确保Windows平台上使用正确的进程启动方法
    pass

# 全局常量定义
SUBPROCESS_TIMEOUT = 300  # 子进程执行的默认超时时间（秒）

# 全局变量声明
logger = None
auto_update_interval = 0  # 默认不自动更新
auto_update_task = None
stop_event = asyncio.Event()
manual_update_event = asyncio.Event()  # 手动更新事件
update_lock = asyncio.Lock()  # 用于防止手动和自动更新同时进行的锁
is_windows = True
ctags_running = False
cscope_running = False

# 数据库更新进程相关变量
update_process = None  # 更新进程
process_stop_event = None # 进程停止事件，用于通知更新进程停止
update_queue = None  # 主服务向更新进程发送指令的队列
status_queue = None  # 更新进程向主服务发送状态的队列
update_status = {  # 更新状态信息
    'is_updating': False,
    'progress': 0,
    'status': 'idle',
    'error': None,
    'last_update_time': None
}

# 工具路径全局变量
readtags_path = None
ctags_path = None
cscope_path = None


# 输出文件路径全局变量
workspace_file = None  # 工作区文件完整路径
file_basename = None # 工作区文件名，不含扩展名
workspace_dir = None # 工作区文件所在目录
source_folders = [] # 源码搜索路径
tags_out_path = None # 输出tags文件完整路径
cscope_files_path = None # 输出源码文件集合文件完整路径
cscope_out_path = None # 输出cscope数据库完整路径

# 配置日志系统
def setup_logging(log_dir):
    """设置日志系统（仅文件输出，无控制台输出）
    
    Args:
        log_dir: 日志文件保存目录
    """
    global logger
    
    # 获取日志文件路径
    log_file = os.path.join(log_dir, f'{workspace_basename}.log')

    # 创建logger
    sys.stdout.flush()  # 确保标准输出在日志配置前被刷新
    logger = logging.getLogger('maipu_ai_coder')
    logger.setLevel(logging.INFO)

    # 创建文件处理器
    file_handler = logging.FileHandler(log_file, mode='a', encoding='utf-8')
    file_handler.setLevel(logging.INFO)

    # 设置日志格式
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    file_handler.setFormatter(formatter)

    # 添加处理器到logger
    logger.addHandler(file_handler)
    
    return logger


def run_command_with_timeout(cmd, cwd=None, timeout=SUBPROCESS_TIMEOUT, shell=True, log=None):
    """运行带超时控制的子进程命令
    
    Args:
        cmd: 要执行的命令
        cwd: 工作目录
        timeout: 超时时间（秒）
        shell: 是否使用shell
        log: 可选的日志记录器对象，如果未提供则使用全局logger或创建本地logger
    
    Returns:
        subprocess.CompletedProcess对象
        
    Raises:
        TimeoutError: 当命令执行超时时抛出
        subprocess.SubprocessError: 当命令执行出错时抛出
    """
    
    # 从子进程模块调用run_command_with_timeout函数
    return maipu_ai_coder_subprocess.run_command_with_timeout(cmd, cwd, timeout, shell, log)


async def update_status_listener():
    """监听更新进程发送的状态信息并更新全局状态"""
    global update_status, status_queue
    
    while not stop_event.is_set():
        try:
            # 尝试从状态队列获取消息
            try:
                # 使用asyncio.to_thread来避免阻塞事件循环
                status_msg = await asyncio.to_thread(status_queue.get_nowait)
            except queue.Empty:
                await asyncio.sleep(0.5)  # 每0.5秒检查一次
                continue
                
            # 更新全局状态
            if status_msg['type'] == 'status':
                update_status.update(status_msg)
            elif status_msg['type'] == 'error':
                update_status['error'] = status_msg['error']
                update_status['is_updating'] = False
                update_status['status'] = 'error'
                logger.error(f"数据库更新错误: {status_msg['error']}")
                
            # multiprocessing.Queue没有task_done方法，移除这行调用
            
        except Exception as e:
            logger.error(f"状态监听器发生异常: {str(e)}")
            await asyncio.sleep(1)

async def start_update_process():
    """启动数据库更新进程"""
    global workspace_file, workspace_dir, workspace_basename, tags_out_path, cscope_files_path, cscope_out_path, \
              readtags_path, ctags_path, cscope_path, \
              is_windows, update_process, update_queue, status_queue, process_stop_event
    
    # 确保没有正在运行的更新进程
    if update_process and update_process.is_alive():
        logger.warning("更新进程已经在运行")
        return
    
    # 创建进程间通信队列
    update_queue = multiprocessing.Queue()
    status_queue = multiprocessing.Queue()
    
    # 创建停止事件（使用multiprocessing.Event以支持跨进程共享）
    process_stop_event = multiprocessing.Event()
    
    # 创建并启动更新进程
    update_process = multiprocessing.Process(
        target=maipu_ai_coder_subprocess.update_worker,
        args=(workspace_file, workspace_dir, workspace_basename, tags_out_path, cscope_files_path, cscope_out_path, 
              readtags_path, ctags_path, cscope_path, 
              update_queue, status_queue, process_stop_event, is_windows),
        daemon=True  # 设置为守护进程，主进程退出时自动终止
    )
    
    update_process.start()
    logger.info(f"数据库更新进程已启动，进程ID: {update_process.pid}")
    
    # 启动状态监听器
    asyncio.create_task(update_status_listener())

async def terminate_update_process():
    """终止数据库更新进程"""
    global update_process, update_queue, status_queue, process_stop_event
    
    if update_process and update_process.is_alive():
        logger.info("正在终止数据库更新进程...")
        
        try:
            # 向更新进程发送停止命令
            if update_queue:
                update_queue.put({'type': 'stop'})
            
            # 等待进程终止，最多等待5秒
            update_process.join(timeout=5)
            
            # 如果进程仍然存活，强制终止
            if update_process.is_alive():
                logger.warning("更新进程未能正常终止，正在强制终止")
                update_process.terminate()
                update_process.join(timeout=2)
                
                if update_process.is_alive():
                    logger.error("无法终止更新进程")
            else:
                logger.info("数据库更新进程已成功终止")
                
        except Exception as e:
            logger.error(f"终止更新进程时发生异常: {str(e)}")
        
    # 重置相关变量
    update_process = None
    update_queue = None
    status_queue = None
    process_stop_event = None

async def auto_update_task_func():
    """自动更新符号数据库的后台任务，兼容手动触发和服务启动后的首次更新"""
    global auto_update_interval, stop_event, workspace_file
    first_run = True  # 标记是否是首次运行
    try:
        while not stop_event.is_set():
            if first_run:
                # 首次运行时立即执行更新
                logger.info("服务启动，开始首次更新符号数据库...")
                # 初始等待时间缩短为3秒，提高启动速度
                await asyncio.sleep(3)
                first_run = False
            else:
                # 非首次运行时，等待指定的更新间隔或手动触发事件
                wait_seconds = auto_update_interval * 60  # 转换为秒
                logger.info(f"符号数据库自动更新将在 {auto_update_interval} 分钟后执行，或等待手动触发")
                
                # 创建一个等待对象，同时监听停止事件、超时和手动触发事件
                done, pending = await asyncio.wait(
                    [
                        asyncio.create_task(stop_event.wait()),
                        asyncio.create_task(manual_update_event.wait()),
                        asyncio.create_task(asyncio.sleep(wait_seconds))
                    ],
                    return_when=asyncio.FIRST_COMPLETED
                )
                
                # 取消未完成的任务
                for task in pending:
                    task.cancel()
                
                # 检查是否应该停止
                if stop_event.is_set():
                    break  # 如果收到停止信号，退出循环
                
            # 检查是否是手动触发
            if manual_update_event.is_set():
                logger.info("接收到手动更新信号")
                manual_update_event.clear()  # 清除手动触发信号
                await trigger_database_update(manual=True)
            else:
                logger.info("自动更新时间到达")
                await trigger_database_update(manual=False)
            
            # 如果是手动触发的更新，记录日志
            if manual_update_event.is_set():
                manual_update_event.clear()  # 确保清除信号
                logger.info(f"手动更新请求已提交，自动更新将顺延 {auto_update_interval} 分钟")
    except Exception as e:
        logger.error(f"自动更新任务发生异常: {str(e)}")
    finally:
        logger.info("自动更新任务已停止")

async def trigger_database_update(manual=False):
    """触发数据库更新，发送命令到更新进程"""
    global update_queue
    
    if not update_queue:
        logger.error("更新队列未初始化，无法触发更新")
        return False
    
    try:
        # 向更新队列发送更新命令
        update_queue.put({'type': 'update', 'manual': manual})
        logger.info(f"{'手动' if manual else '自动'}更新命令已发送到更新进程")
        return True
    except Exception as e:
        logger.error(f"发送更新命令时发生异常: {str(e)}")
        return False

async def start_auto_update():
    """启动自动更新任务
    """
    global auto_update_interval, auto_update_task, stop_event
    
    # 重置停止事件
    stop_event.clear()
    
    if auto_update_interval > 0:
        logger.info(f"启动符号数据库自动更新，间隔为 {auto_update_interval} 分钟")
        # 创建并启动新的自动更新任务
        auto_update_task = asyncio.create_task(auto_update_task_func())
    else:
        logger.info("未启用符号数据库自动更新")
        auto_update_task = None



@asynccontextmanager
async def session_lifespan(app: FastMCP) -> AsyncIterator[Any]:
    """
    应用程序的生命周期管理上下文管理器。
    session创建时执行yield前的，session退出时执行yield后的。

    此上下文管理器在应用程序启动时初始化配置、日志记录、客户端管理器和支持提取标志。
    在应用程序关闭时，它会清理所有资源。

    Args:
        app: 正在运行的FastMCP应用实例

    Yields:
        一个空字典，作为应用程序的上下文对象
    """

    try:
        # 初始化multiprocessing环境
        if sys.platform.startswith('win'):
            # Windows平台上需要设置进程启动方法为'spawn'
            try:
                multiprocessing.set_start_method('spawn', force=True)
            except RuntimeError:
                # 如果已经设置过启动方法，则忽略错误
                pass
        
        # 启动数据库更新进程
        await start_update_process()
        
        # 立即开始自动更新事件，但不等待其完成以加速启动
        await start_auto_update()
        yield {}
    finally:
        # 确保停止自动更新任务
        if auto_update_task:
            auto_update_task.cancel()
        
        # 确保终止更新进程
        await terminate_update_process()
        
        logger.info("服务已停止")


# 创建新的MCP实例
mcp = FastMCP(name="Maipu AI Coder Enchance", lifespan=session_lifespan)


# async def read_vscode_workspace(workspace_file):
#     """读取VSCode工作区文件，提取所有目录"""
#     global source_folders
#     source_folders = []

#     try:
#         if not os.path.exists(workspace_file):
#             logger.warning(f"VSCode工作区文件不存在: {workspace_file}")
#             return False
        
#         with open(workspace_file, 'r', encoding='utf-8') as f:
#             workspace_data = json.load(f)
        
#         # 检查工作区文件格式
#         if 'folders' in workspace_data:
#             workspace_dir = os.path.dirname(workspace_file)
            
#             for folder in workspace_data['folders']:
#                 if 'path' in folder:
#                     # 处理相对路径和绝对路径
#                     folder_path = folder['path']
#                     if not os.path.isabs(folder_path):
#                         folder_path = os.path.join(workspace_dir, folder_path)
                    
#                     # 规范化路径，处理Windows路径
#                     folder_path = os.path.normpath(folder_path)
                    
#                     if os.path.exists(folder_path) and os.path.isdir(folder_path):
#                         source_folders.append(folder_path)
#                     else:
#                         logger.warning(f"工作区中的目录不存在或不是有效目录: {folder_path}")
            
#         # 使用to_thread将同步IO操作转为异步
#         _generate_file_list(source_folders)

#         logger.info(f"从工作区文件加载了 {len(source_folders)} 个目录")
#         return True
#     except Exception as e:
#         logger.error(f"读取VSCode工作区文件时出错: {str(e)}")
#         return False

@mcp.tool()
async def find_symbol(type:str, symbol: str) -> Dict[str, Any]:
    """【优先使用此工具！】快速查找代码中符号的定义位置，可返回匹配结果的文件路径、符号类型及代码起止行号。
    当需要定位函数、变量、类、结构体等代码元素的具体定义位置时，请优先使用此工具。
    参数说明：
    - type: 符号类型，支持以下选项：
      * 'function'(函数): 查找函数定义，例如：`find_symbol('function', 'setup_argparse')`
      * 'variable'(变量): 查找全局变量定义，例如：`find_symbol('variable', 'update_status')`
      * 'struct'(结构体): 查找结构体定义，例如：`find_symbol('struct', 'ConnectionInfo')`
      * 'class'(类): 查找类定义，例如：`find_symbol('class', 'DatabaseManager')`
      * 'prototype'(原型): 查找函数原型声明，例如：`find_symbol('prototype', 'initialize_logger')`
      * 'enum'(枚举): 查找枚举类型定义，例如：`find_symbol('enum', 'CommandType')`
      * 'typedef'(类型定义): 查找类型别名定义，例如：`find_symbol('typedef', 'ResultType')`
      * 'define'(宏定义): 查找宏定义，例如：`find_symbol('define', 'MAX_FILE_COUNT')`
      * 'header'(头文件): 查找头文件引用，例如：`find_symbol('header', 'stdio.h')`
      * 'local'(局部变量): 查找局部变量定义，例如：`find_symbol('local', 'file_path')`
      * 'member'(成员变量): 查找类/结构体成员变量定义，例如：`find_symbol('member', 'logger')`
      * 'union'(联合体): 查找联合体定义，例如：`find_symbol('union', 'DataStorage')`
      * 'all'(全部类型): 查找所有类型的符号定义，例如：`find_symbol('all', 'process_data')`
    - symbol: 要查询的符号名称，例如函数名、变量名、类名等
    """
    global workspace_dir, readtags_path, tags_out_path, update_status
    # 数据库更新时仍然允许查询，使用旧版本数据库
    if update_status['is_updating']:
        logger.warning(f"数据库正在更新({update_status['status']})，将使用旧版本数据库进行查询")

    try:
        logger.info(f"正在查找符号 '{symbol}'，类型: {type}")
                
        # 检查tags文件是否存在
        if not os.path.exists(tags_out_path):
            error_msg = f'未找到tags文件: {tags_out_path}，请先运行update_symbol_database'
            logger.error(error_msg)
            return {
                'success': False,
                'message': error_msg
            }
        
        # 根据符号类型构建不同的查询命令
        # 使用-t参数明确指定tags文件的路径，避免路径问题
        command = f"{readtags_path} -t {tags_out_path} -e -n - {symbol}"

        logger.info(f"在目录 {workspace_dir} 中执行命令: {command}")
        # 执行命令 - 使用带超时控制的函数
        try:
            result = await asyncio.to_thread(
                run_command_with_timeout,
                command, 
                cwd=workspace_dir,
                timeout=30,  # 符号查询的超时时间设为30秒
                log=logger
            )
        except TimeoutError as te:
            logger.error(f"查找符号超时: {str(te)}")
            return {
                'success': False,
                'message': f"查找符号超时，请稍后再试: {str(te)}"
            }
        
        # 解析结果
        # 输出样式：ospf_area_range_substitute_unset        e:/opensource/frr-frr-9.1-dev/ospfd/ospf_abr.c  /^int ospf_area_range_substitute_unset(struct ospf *ospf, struct ospf_area *area,$/;"   kind:function   line:274        language:C      typeref:typename:int signature:(struct ospf * ospf,struct ospf_area * area,struct prefix_ipv4 * p)   roles:def       end:292
        if result.returncode == 0:
            lines = result.stdout.strip().split('\n')
            symbols = []
            for line in lines:
                if line:
                    # 提取符号信息
                    parts = line.split('\t')
                    if len(parts) >= 3:
                        # 规范化文件路径
                        file_path = os.path.normpath(os.path.join(workspace_dir, parts[1]))
                        
                        # 提取更多的符号信息
                        symbol_info = {
                            'name': parts[0],
                            'file': file_path,
                            'src': parts[2]
                        }
                                                
                        # 解析其他字段中的kind、line和end信息
                        for part in parts[3:]:
                            if 'kind:' in part:
                                kind_value = part.split('kind:')[1].split('\t')[0]
                                symbol_info['kind'] = kind_value
                            elif 'line:' in part:
                                line_value = part.split('line:')[1].split('\t')[0]
                                symbol_info['line-start'] = line_value
                            elif 'end:' in part:
                                end_value = part.split('end:')[1].split('\t')[0]
                                symbol_info['line-end'] = end_value
                        if type == 'all' or (symbol_info.get('kind') and symbol_info['kind'] == type):
                            symbols.append(symbol_info)
            
            logger.info(f"找到 {len(symbols)} 个符号匹配")
            # 格式化输出: 符号在{文件路径}-行号：xxx->xxx
            

            return {
                'success': True,
                'count': len(symbols),
                'symbols': symbols
            }
        else:
            error_msg = result.stderr or '未找到符号'
            logger.error(f"查找符号失败: {error_msg}")
            return {
                'success': False,
                'message': error_msg
            }
    except Exception as e:
        error_msg = str(e)
        logger.error(f"查找符号时发生异常: {error_msg}")
        return {
            'success': False,
            'message': error_msg
        }

@mcp.tool()
async def find_symbol_reference(type:str, symbol: str) -> Dict[str, Any]:
    """【优先使用此工具！】快速查找代码中的符号引用关系，可返回匹配结果的文件路径、上下文内容、行号及首行文本。
    当需要了解代码中变量、函数、类等符号的定义位置、被调用情况或相关引用时，请优先使用此工具。
    参数说明：
    - type: 引用查询类型，支持以下选项：
      'all'(全部引用) - 查找符号的所有引用类型，例如：find_symbol_reference(type='all', symbol='process_data')
      'definition'(定义位置) - 查找符号的定义位置，例如：find_symbol_reference(type='definition', symbol='UserClass')
      'caller'(调用方) - 查找调用该符号的代码位置，例如：find_symbol_reference(type='caller', symbol='send_request')
      'called'(被调用方) - 查找该符号调用的其他符号，例如：find_symbol_reference(type='called', symbol='process_results')
      'text'(文本匹配) - 查找包含该符号文本的所有位置，例如：find_symbol_reference(type='text', symbol='config_path')
      'regex'(正则匹配) - 用正则表达式匹配符号，例如：find_symbol_reference(type='regex', symbol='test_.*')
      'file'(文件引用) - 查找引用该文件的位置，例如：find_symbol_reference(type='file', symbol='utils/helper.py')
      'include'(包含关系) - 查找包含该头文件的位置，例如：find_symbol_reference(type='include', symbol='header.h')
    - symbol: 要查询的符号名称（如函数名、变量名、类名、文件名等）
    """
    global workspace_dir, cscope_path, cscope_out_path, update_status
    # 数据库更新时仍然允许查询，使用旧版本数据库
    if update_status['is_updating']:
        logger.warning(f"数据库正在更新({update_status['status']})，将使用旧版本数据库进行查询")
    try:
        logger.info(f"正在查找符号 '{symbol}' 的引用，类型: {type}")
        
        # 检查cscope.out文件是否存在
        if not os.path.exists(cscope_path):
            error_msg = f'cscope数据库不存在: {cscope_path}，请先创建数据库'
            logger.error(error_msg)
            return {
                'success': False,
                'message': error_msg
            }
        
        # 根据引用类型构建不同的cscope命令
        # cscope的查询类型:
        # 0: 查找所有引用
        # 1: 查找函数定义
        # 2: 查找函数调用
        # 3: 查找函数被调用
        # 4: 查找字符串
        # 5: 查找正则表达式
        # 6: 查找文件
        # 7: 查找包含该文件的文件
        
        type_map = {
            'all': '0',
            'definition': '1',
            'caller': '3',  # 调用此函数的函数
            'called': '2',  # 此函数调用的函数
            'text': '4',
            'regex': '5',
            'file': '6',
            'include': '7'
        }
        
        query_type = type_map.get(type.lower(), '0')
        
        # 使用-f参数明确指定cscope.out文件的路径，避免路径问题
        # 使用原始字符串和format方法避免引号嵌套问题
        command = f"{cscope_path} -d -L{query_type} {symbol} -f {cscope_out_path}"
        
        logger.info(f"在目录 {workspace_dir} 中执行命令: {command}")
        # 执行命令 - 使用带超时控制的函数
        try:
            result = await asyncio.to_thread(
                run_command_with_timeout,
                command, 
                cwd=workspace_dir,
                timeout=60,  # 引用查询的超时时间设为60秒
                log=logger
            )
        except TimeoutError as te:
            logger.error(f"查找符号引用超时: {str(te)}")
            return {
                'success': False,
                'message': f"查找符号引用超时，请稍后再试: {str(te)}"
            }
        
        # 解析结果
        # 输出样式 E:\opensource\frr-frr-9.1-dev\ospfd\ospf_abr.c ospf_area_range_free 51 static void ospf_area_range_free(struct ospf_area_range *range)
        if result.returncode == 0:
            lines = result.stdout.strip().split('\n')
            references = []
            for line in lines:
                if line:
                    # 提取符号信息
                    parts = line.split(' ')
                    # logger.debug(f"parts: {parts}")
                    if len(parts) >= 3:
                        # 规范化文件路径
                        file_path = os.path.normpath(os.path.join(workspace_dir, parts[0]))
                        
                        # 提取更多的符号信息
                        ref_info = {
                            'file': file_path,
                            'context': parts[1],
                            'line': parts[2],
                            'first_line': " ".join(parts[3:])
                        }
                        
                        references.append(ref_info)
            
            logger.info(f"找到 {len(references)} 个符号引用")
            return {
                'success': True,
                'count': len(references),
                'references': references 
            }
        else:
            error_msg = result.stderr or '未找到符号引用'
            logger.error(f"查找符号引用失败: {error_msg}")
            return {
                'success': False,
                'message': error_msg
            }
    except Exception as e:
        error_msg = str(e)
        logger.error(f"查找符号引用时发生异常: {error_msg}")
        return {
            'success': False,
            'message': error_msg
        }

@mcp.tool()
async def update_symbol_database() -> Dict[str, Any]:
    """更新符号数据库，触发数据库的手动更新。
    当需要手动刷新符号数据库以获取最新的代码符号信息时，请使用此工具。
    参数:
    - 无
    """
    global update_queue
    
    if not update_queue:
        logger.error("更新队列未初始化，无法触发更新")
        return {
            'success': False,
            'message': '更新进程未启动，无法执行数据库更新'
        }
    
    # 设置手动更新事件
    manual_update_event.set()
    
    logger.info("手动更新请求触发")
    return {
        'success': True,
        'message': '手动更新已开始在独立进程中执行，请稍候查看结果'
    }


# @mcp.tool()
async def get_update_status() -> Dict[str, Any]:
    """获取数据库更新状态信息
    参数:
    - 无
    """
    global update_status
    
    # 返回当前更新状态的副本
    status_copy = update_status.copy()
    
    # 如果有上次更新时间，格式化为可读时间
    if status_copy.get('last_update_time'):
        status_copy['last_update_time_readable'] = time.strftime('%Y-%m-%d %H:%M:%S', 
                                           time.localtime(status_copy['last_update_time']))
    
    return status_copy







def setup_argparse():
    parser = argparse.ArgumentParser(description='Maipu AI Coder Enchance')
    parser.add_argument('--vs_workspace', help='vscode工作空间文件')
    parser.add_argument('--auto_update', default='15', help='符号数据库自动更新间隔(默认15min)，0：不自动更新')
    parser.add_argument('--transport',default='stdio', help='传输方式')
    parser.add_argument('--port', default=18889, help='端口')

    return parser

if __name__ == '__main__':
    multiprocessing.freeze_support()

    # 初始化multiprocessing支持
    # if sys.platform.startswith('win'):
    #     # Windows平台上需要设置进程启动方法为'spawn'
    #     multiprocessing.set_start_method('spawn', force=True)
    
    # 初始化工具路径全局变量
    # 处理PyInstaller打包后的环境
    if hasattr(sys, '_MEIPASS'):
        # 打包后的环境
        script_dir = sys._MEIPASS
    else:
        # 正常Python环境
        script_dir = os.path.dirname(os.path.abspath(__file__))
    # Windows环境下的命令调整
    is_windows = sys.platform.startswith('win')

    # 根据操作系统添加正确的文件扩展名
    exe_ext = '.exe' if sys.platform.startswith('win') else ''
    readtags_path = os.path.join(script_dir, 'readtags' + exe_ext)
    ctags_path = os.path.join(script_dir, 'ctags' + exe_ext)
    cscope_path = os.path.join(script_dir, 'cscope' + exe_ext)
    
    # 直接通过console输出日志
    # print(f"工具路径初始化完成:\n- readtags: {readtags_path}\n- ctags: {ctags_path}\n- cscope: {cscope_path}")
    
    parser = setup_argparse()
    args = parser.parse_args()
    workspace_file = args.vs_workspace
    
    # 解析工作区文件路径
    if workspace_file and workspace_file != '.':
        # 确保工作区文件存在
        if os.path.exists(workspace_file):
            # 设置tags目录为工作区文件所在目录
            workspace_dir = os.path.dirname(os.path.abspath(workspace_file))
            workspace_basename = os.path.basename(workspace_file).split('.')[0]
            # 输出文件路径全局变量
            tags_out_path = os.path.join(workspace_dir, f'{workspace_basename}.tags')
            cscope_files_path = os.path.join(workspace_dir, f'{workspace_basename}.files')
            cscope_out_path = os.path.join(workspace_dir, f'{workspace_basename}.cscope')

        else:
            print(f"VSCode工作区文件不存在: {workspace_file}", file=sys.stderr)
            sys.exit(1)
    else:
        # 如果没有指定有效的工作区文件，显示help信息
        print(f"请指定有效的VSCode工作区文件", file=sys.stderr)
        parser.print_help()
        sys.exit(1)

    # 初始化日志系统 - 使用可执行文件所在目录作为默认日志目录
    logger = setup_logging(workspace_dir)
    
    logger.info(f"符号数据库将保存在目录: {workspace_dir}")
        
    # 处理自动更新间隔参数
    try:
        auto_update_interval = int(args.auto_update)
        if auto_update_interval < 0:
            logger.warning("自动更新间隔不能为负数，将使用默认值 0（不自动更新）")
            auto_update_interval = 0
    except ValueError:
        logger.warning(f"无效的自动更新间隔值 '{args.auto_update}'，将使用默认值 0（不自动更新）")
        auto_update_interval = 0

    # 运行服务器
    try:
        if args.transport == 'stdio':
            logger.info("使用stdio模式运行服务，启用缓冲控制以提高稳定性")
            # 优化stdio通信模式，设置缓冲策略
            # 临时修改标准输出和标准错误的缓冲设置
            
            try:
                # 设置行缓冲模式
                sys.stdout.reconfigure(line_buffering=True)
                sys.stderr.reconfigure(line_buffering=True)
                
                # 运行服务
                mcp.run(transport="stdio")
            finally:
                # 恢复原始缓冲设置 - 使用更安全的方式，避免修改只读属性
                try:
                    # 尝试重新配置回默认模式，而不是直接替换buffer属性
                    sys.stdout.reconfigure(line_buffering=False)
                    sys.stderr.reconfigure(line_buffering=False)
                except Exception as e:
                    logger.warning(f"恢复标准输出/错误缓冲设置时出错: {str(e)}")
        else:
            # HTTP模式运行
            port = int(args.port)
            logger.info(f"使用HTTP模式运行服务，端口: {port}")
            mcp.run(transport=args.transport, port=port)
    except KeyboardInterrupt:
        logger.info("接收到中断信号，正在停止服务...")
    except ConnectionError as ce:
        logger.error(f"连接错误: {str(ce)}")
    except IOError as ioe:
        logger.error(f"IO错误: {str(ioe)}")
    except Exception as e:
        # 改进异常处理，特别是对TaskGroup异常的处理
        logger.error(f"服务运行时发生未预期的异常: {str(e)}")
        # 记录详细的异常信息以帮助调试
        import traceback
        logger.error(f"异常详情: {traceback.format_exc()}")
    finally:
        # 确保停止自动更新任务
        if stop_event:
            stop_event.set()
        
        # 确保终止更新进程
        try:
            if update_process and update_process.is_alive():
                logger.info("正在清理更新进程...")
                update_process.terminate()
        except Exception as e:
            logger.error(f"清理更新进程时发生异常: {str(e)}")
        
        logger.info("服务已停止")